package cn.modoumama.excelUilt.util;

import cn.modoumama.common.tools.FileUtils;
import cn.modoumama.common.tools.ObjectUtils;
import cn.modoumama.common.tools.StringUtils;
import cn.modoumama.common.tools.VerifyObject;
import cn.modoumama.excelUilt.po.CellEntity;
import cn.modoumama.excelUilt.po.SheetEntity;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.Date;
import java.util.List;

public class ExportExcel {
    private static Logger logger = LoggerFactory.getLogger(ExportExcel.class);

    private ExportExcel() {
        super();
    }
    
    /**
     * 导出Excel<br>
     * <br>  
     * 创建人：邓强   <br>
     * 创建时间：2018年2月10日 下午5:22:22    <br> 
     * 修改人：  <br>
     * 修改时间：2018年2月10日 下午5:22:22   <br>  
     * 修改备注：     <br> 
     * @param sheetEntity
     * @param path
     * @return
     */
    public static Workbook writeExcel(SheetEntity sheetEntity, String path){
		File file = FileUtils.getFile(path);
		return writeExcel(sheetEntity, file);
    }
    
    /**
     * 导出Excel<br>
     * <br>  
     * 创建人：邓强   <br>
     * 创建时间：2018年2月10日 下午5:22:46    <br> 
     * 修改人：  <br>
     * 修改时间：2018年2月10日 下午5:22:46   <br>  
     * 修改备注：     <br> 
     * @param sheetEntity
     * @param file
     * @return
     */
    public static Workbook writeExcel(SheetEntity sheetEntity, File file){
    	Workbook workbook=null;
    	OutputStream out = null;
    	try {
			out = new FileOutputStream(file);
			workbook = writeExcel(sheetEntity, out);
		} catch (FileNotFoundException e) {
			logger.error("文件{}未找到",file.getPath());
		}finally{
			if(out != null){
				try {
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return workbook;
    }
    
    /**
     * 导出Excel<br>
     * <br>  
     * 创建人：邓强   <br>
     * 创建时间：2018年2月10日 下午5:22:56    <br> 
     * 修改人：  <br>
     * 修改时间：2018年2月10日 下午5:22:56   <br>  
     * 修改备注：     <br> 
     * @param sheetEntity
     * @param out
     * @return
     */
    public static Workbook writeExcel(SheetEntity sheetEntity, OutputStream out){
    	// 声明一个工作薄
        if(sheetEntity.getWorkbook() == null){
            Workbook workbook = createExcel();
            sheetEntity.setWorkbook(workbook);
        }

		createExcel(sheetEntity);
		writeExcel(sheetEntity.getWorkbook(), out);
		return sheetEntity.getWorkbook();
    }
    
    /**
     * 导出多页Excel<br>
     * <br>  
     * 创建人：邓强   <br>
     * 创建时间：2018年2月10日 下午5:23:09    <br> 
     * 修改人：  <br>
     * 修改时间：2018年2月10日 下午5:23:09   <br>  
     * 修改备注：     <br> 
     * @param sheetEntitys
     * @param path
     * @return
     */
    public static Workbook writeExcel(List<SheetEntity> sheetEntitys, String path){
		File file = FileUtils.getFile(path);
		return writeExcel(sheetEntitys, file);
    }
    
    /**
     * 导出多页Excel<br>
     * <br>  
     * 创建人：邓强   <br>
     * 创建时间：2018年2月10日 下午5:24:24    <br> 
     * 修改人：  <br>
     * 修改时间：2018年2月10日 下午5:24:24   <br>  
     * 修改备注：     <br> 
     * @param sheetEntitys
     * @param file
     * @return
     */
    public static Workbook writeExcel(List<SheetEntity> sheetEntitys, File file){
    	Workbook workbook=null;
    	OutputStream out = null;
    	try {
			out = new FileOutputStream(file);
			workbook = writeExcel(sheetEntitys, out);
		} catch (FileNotFoundException e) {
			logger.error("文件{}未找到",file.getPath());
		}finally{
			if(out != null){
				try {
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return workbook;
    }
    
    /**
     * 导出多页Excel<br>
     * <br>  
     * 创建人：邓强   <br>
     * 创建时间：2018年2月10日 下午5:24:35    <br> 
     * 修改人：  <br>
     * 修改时间：2018年2月10日 下午5:24:35   <br>  
     * 修改备注：     <br> 
     * @param sheetEntitys
     * @param out
     * @return
     */
    public static Workbook writeExcel(List<SheetEntity> sheetEntitys, OutputStream out){
    	// 声明一个工作薄
		Workbook workbook = createExcel();
		for (SheetEntity sheetEntity : sheetEntitys) {
            sheetEntity.setWorkbook(workbook);
			createExcel(sheetEntity);
		}
		writeExcel(workbook, out);
		return workbook;
    }

    /**
     * 获取一个Workbook对象<br>
     * <br>  
     * 创建人：邓强   <br>
     * 创建时间：2018年2月10日 上午10:40:35    <br> 
     * 修改人：  <br>
     * 修改时间：2018年2月10日 上午10:40:35   <br>  
     * 修改备注：     <br> 
     * @return
     */
    public static Workbook createExcel(){
    	// 声明一个工作薄
    	return new SXSSFWorkbook();
    }
    
   /**
    * 创建Excel的一页数据<br>
    * <br>  
    * 创建人：邓强   <br>
    * 创建时间：2018年2月10日 下午5:24:51    <br>
    * @param sheetEntity
    */
    private static void createExcel(SheetEntity sheetEntity){
        if(sheetEntity.getData() == null || sheetEntity.getData().isEmpty()){
            throw new RuntimeException("没有数据");
        }
    		try {
                Workbook workbook = sheetEntity.getWorkbook();
    			sheetEntity = sheetEntity.clone();

				// 初始化样式
				//头部样式
				if(sheetEntity.getCallStyle("head") == null){
					CellStyle cellStyle = workbook.createCellStyle();

					cellStyle.setAlignment(HorizontalAlignment.CENTER);
					cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);

					cellStyle.setBorderBottom(BorderStyle.THIN); //下边框
					cellStyle.setBorderLeft(BorderStyle.THIN);//左边框
					cellStyle.setBorderTop(BorderStyle.THIN);//上边框
					cellStyle.setBorderRight(BorderStyle.THIN);//右边框

					cellStyle.setFillForegroundColor(HSSFColor.HSSFColorPredefined.SKY_BLUE.getIndex());
					cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
					Font font = workbook.createFont();
					font.setBold(true);//粗体显示
					cellStyle.setFont(font);

    				if(sheetEntity.getHeadCellStyle() != null){
						sheetEntity.getHeadCellStyle().setCellStyle(cellStyle);
					}

					sheetEntity.addCallStyles("head", cellStyle);
				}

				//列表样式
				if(sheetEntity.getCallStyle("list") == null){
					CellStyle cellStyle = workbook.createCellStyle();

					cellStyle.setAlignment(HorizontalAlignment.GENERAL);
					cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);

					cellStyle.setBorderBottom(BorderStyle.THIN); //下边框
					cellStyle.setBorderLeft(BorderStyle.THIN);//左边框
					cellStyle.setBorderTop(BorderStyle.THIN);//上边框
					cellStyle.setBorderRight(BorderStyle.THIN);//右边框

					if(sheetEntity.getListCellStyle() != null){
						sheetEntity.getListCellStyle().setCellStyle(cellStyle);
					}

					sheetEntity.addCallStyles("list", cellStyle);
				}

    			DataFormat dataFormat = workbook.createDataFormat();
				// 生成一个表格
				Sheet sheet;
				//读取页
				if(StringUtils.isNotBlank(sheetEntity.getName())){
					sheet = workbook.getSheet(sheetEntity.getName());
				}else{
					sheet = workbook.getSheetAt(sheetEntity.getIndex());
				}

    			if(sheet == null){
    				sheet = workbook.createSheet(sheetEntity.getName());
    			}
				sheet.setDefaultColumnWidth(sheetEntity.getWidth()); 
				sheet.setDefaultRowHeightInPoints(sheetEntity.getHeight());
				List<?> data = sheetEntity.getData();
				if(data!=null && data.size()>0){
					Object obj= data.get(0);
					for (Integer index : sheetEntity.keySet()) {
						//设置默认宽度
						CellEntity cellEntry = sheetEntity.get(index).getValue();
						String fieldName = sheetEntity.get(index).getKey();
						Class<?> clazz = ObjectUtils.getPropertyType(obj.getClass(), fieldName);
						Integer width = cellEntry.getWidth();
						if(width != null){
							width = width*256;
							sheet.setColumnWidth(index, width);
						}

						CellStyle cellStyle = sheetEntity.getCallStyle("list");
						CellStyle newCellStyle = workbook.createCellStyle();
						newCellStyle.cloneStyleFrom(cellStyle);


				    	String  format = cellEntry.getFormat();
				    	if(clazz.getName().equals(Date.class.getName()) || Date.class.isAssignableFrom(clazz)){
				    		format = StringUtils.isNotBlank(format) ? format : sheetEntity.getDateFormat();
				    	}
				    	
				    	if(StringUtils.isNotBlank(format)){
				    		short formatIndex = dataFormat.getFormat(format);
							newCellStyle.setDataFormat(formatIndex);
				    	}
				    	
				    	Font font = cellEntry.getFont();
				    	if(font != null){
							newCellStyle.setFont(font);
				    	}
				    	
				    	cellEntry.setCellStyle(newCellStyle);
					}
				}
				
				Integer lastRowNum = sheet.getLastRowNum();
				Integer height = sheetEntity.getHeight() * 20;

				if (sheetEntity.isHead()) {
					Row row = sheet.createRow(sheetEntity.getHeadRowNumber());
					row.setHeight(height.shortValue());
					sheetEntity.rowHead(row);
				}

				if(sheetEntity.getFirst() <= lastRowNum){
					sheet.shiftRows(sheetEntity.getFirst() ,lastRowNum, data.size(),true, true );
				}

				for (int i = 0; i < data.size(); i++) {
					Row row = sheet.createRow(sheetEntity.getFirst()+i);
					row.setHeight(height.shortValue());
					sheetEntity.rowData(row, data.get(i));
				}
				
				
			} catch (Exception e) {
    			e.printStackTrace();
				throw new RuntimeException(e);
			}
    }
    
    /**
     * 把Excel数据写入文件<br>
     * <br>  
     * 创建人：邓强   <br>
     * 创建时间：2018年2月10日 下午5:25:25    <br>
     * @param workbook
     * @param path
     */
    public static void writeExcel(Workbook workbook,String path){
    	File file = new File(path);
    	writeExcel(workbook, file);
    }
    
    /**
     * 把Excel数据写入文件<br>
     * <br>  
     * 创建人：邓强   <br>
     * 创建时间：2018年2月10日 下午5:25:48    <br>
     * @param workbook
     * @param file
     */
    public static void writeExcel(Workbook workbook,File file){
    	try {
			OutputStream out = new FileOutputStream(file);
			writeExcel(workbook, out);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
    }
    
    /**
     * 把Excel数据写入输入流<br>
     * <br>  
     * 创建人：邓强   <br>
     * 创建时间：2018年2月10日 下午5:25:55    <br>
     * @param workbook
     * @param out
     */
    public static void writeExcel(Workbook workbook,OutputStream out){
    	try {
    		workbook.write(out);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
    }

	/**
	 * 通过模板写入数据
	 * @param templatePath	模板文件路径
	 * @param sheetEntity  配置属性和数据
	 * @param path			输出文件路径
	 * @return
	 */
	public static Workbook templateExportExcel(String templatePath,SheetEntity sheetEntity, String path){
		return templateExportExcel(new File(templatePath),sheetEntity, path);
	}

	/**
	 * 通过模板写入数据
	 * @param templatePath	模板文件路径
	 * @param sheetEntity  配置属性和数据
	 * @param outFile		输出文件
	 * @return
	 */
	public static Workbook templateExportExcel(String templatePath,SheetEntity sheetEntity, File outFile){
		return templateExportExcel(new File(templatePath),sheetEntity, outFile);
	}

	/**
	 * 通过模板写入数据
	 * @param templateFile	模板文件
	 * @param sheetEntity  配置属性和数据
	 * @param path			输出文件路径
	 * @return
	 */
	public static Workbook templateExportExcel(File templateFile,SheetEntity sheetEntity, String path){
		try {
			return templateExportExcel(templateFile,sheetEntity, new File(path));
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 通过模板写入数据
	 * @param templateFile	模板文件
	 * @param sheetEntity  配置属性和数据
	 * @param outFile		输出文件
	 * @return
	 */
	public static Workbook templateExportExcel(File templateFile,SheetEntity sheetEntity, File outFile){
		Workbook workbook = null;
		InputStream inputStream = null;
		try {
			inputStream = new FileInputStream(templateFile);
			workbook = templateExportExcel(new FileInputStream(templateFile),sheetEntity, outFile);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}finally {
			if(inputStream != null){
				try {
					inputStream.close();
				} catch (Exception e) {
					throw new RuntimeException(e);
				}
			}
		}
		return workbook;
	}

	/**
	 * 通过模板写入数据
	 * @param inputStream	模板文件输入流
	 * @param sheetEntity  配置属性和数据
	 * @param path			输出文件地址
	 * @return
	 */
	public static Workbook templateExportExcel(InputStream inputStream, SheetEntity sheetEntity, String path){
		try {
			templateExportExcel(inputStream, sheetEntity, FileUtils.getFile(path));
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		return null;

	}

	/**
	 * 通过模板写入数据
	 * @param inputStream	模板文件输入流
	 * @param sheetEntity  配置属性和数据
	 * @param outFile		输出文件
	 * @return
	 */
	public static Workbook templateExportExcel(InputStream inputStream, SheetEntity sheetEntity, File outFile){
		OutputStream outputStream = null;
		try {
			outputStream = new FileOutputStream(outFile);
			return templateExportExcel(inputStream,sheetEntity, outputStream);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}finally {
			if(outputStream != null){
				try {
					outputStream.close();
				} catch (Exception e) {
					throw new RuntimeException(e);
				}
			}
		}
	}

	/**
	 * 通过模板写入数据
	 * @param templatePath	模板文件路径
	 * @param sheetEntity	配置属性和数据
	 * @param out			输出流
	 * @return
	 */
	public static Workbook templateExportExcel(String templatePath, SheetEntity sheetEntity, OutputStream out){
		try {
			return templateExportExcel(new File(templatePath),sheetEntity, out);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 通过模板写入数据
	 * @param templateFile	模板文件
	 * @param sheetEntity	配置属性和数据
	 * @param out			输出流
	 * @return
	 */
	public static Workbook templateExportExcel(File templateFile, SheetEntity sheetEntity, OutputStream out){
		Workbook workbook = null;
		try {
			workbook = WorkbookFactory.create(templateFile);
			sheetEntity.setWorkbook(workbook);
			templateExportExcel(sheetEntity);
			workbook.write(out);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		return workbook;
	}


	/**
	 * 通过模板写入数据
	 * @param inputStream	模板文件输入流
	 * @param sheetEntity	配置属性和数据
	 * @param out			输出流
	 * @return
	 */
	public static Workbook templateExportExcel(InputStream inputStream, SheetEntity sheetEntity, OutputStream out){
		Workbook workbook = null;
		try {
			workbook = WorkbookFactory.create(inputStream);
			sheetEntity.setWorkbook(workbook);
			templateExportExcel(sheetEntity);
			workbook.write(out);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		return workbook;
	}

	/**
	 * 通过模板写入数据
	 * @param templatePath	模板文件路径
	 * @param sheetEntitys  配置属性和数据
	 * @param path			输出文件路径
	 * @return
	 */
	public static Workbook templateExportExcel(String templatePath,List<SheetEntity> sheetEntitys, String path){
		return templateExportExcel(new File(templatePath),sheetEntitys, path);
	}

	/**
	 * 通过模板写入数据
	 * @param templatePath	模板文件路径
	 * @param sheetEntitys  配置属性和数据
	 * @param outFile		输出文件
	 * @return
	 */
	public static Workbook templateExportExcel(String templatePath,List<SheetEntity> sheetEntitys, File outFile){
		return templateExportExcel(new File(templatePath),sheetEntitys, outFile);
	}

	/**
	 * 通过模板写入数据
	 * @param templateFile	模板文件
	 * @param sheetEntitys  配置属性和数据
	 * @param path			输出文件路径
	 * @return
	 */
	public static Workbook templateExportExcel(File templateFile,List<SheetEntity> sheetEntitys, String path){
		try {
			return templateExportExcel(templateFile,sheetEntitys, new File(path));
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 通过模板写入数据
	 * @param templateFile	模板文件
	 * @param sheetEntitys  配置属性和数据
	 * @param outFile		输出文件
	 * @return
	 */
	public static Workbook templateExportExcel(File templateFile,List<SheetEntity> sheetEntitys, File outFile){
		Workbook workbook = null;
		InputStream inputStream = null;
		try {
			inputStream = new FileInputStream(templateFile);
			workbook = templateExportExcel(new FileInputStream(templateFile),sheetEntitys, outFile);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}finally {
			if(inputStream != null){
				try {
					inputStream.close();
				} catch (Exception e) {
					throw new RuntimeException(e);
				}
			}
		}
		return workbook;
	}

	/**
	 * 通过模板写入数据
	 * @param inputStream	模板文件输入流
	 * @param sheetEntitys  配置属性和数据
	 * @param path			输出文件地址
	 * @return
	 */
	public static Workbook templateExportExcel(InputStream inputStream, List<SheetEntity> sheetEntitys, String path){
		try {
			templateExportExcel(inputStream, sheetEntitys, FileUtils.getFile(path));
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		return null;

	}

	/**
	 * 通过模板写入数据
	 * @param inputStream	模板文件输入流
	 * @param sheetEntitys  配置属性和数据
	 * @param outFile		输出文件
	 * @return
	 */
	public static Workbook templateExportExcel(InputStream inputStream, List<SheetEntity> sheetEntitys, File outFile){
		OutputStream outputStream = null;
		try {
			outputStream = new FileOutputStream(outFile);
			return templateExportExcel(inputStream,sheetEntitys, outputStream);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}finally {
			if(outputStream != null){
				try {
					outputStream.close();
				} catch (Exception e) {
					throw new RuntimeException(e);
				}
			}
		}
	}

	/**
	 * 通过模板写入数据
	 * @param templatePath	模板文件路径
	 * @param sheetEntitys  配置属性和数据
	 * @param out		输出流
	 * @return
	 */
	public static Workbook templateExportExcel(String templatePath, List<SheetEntity> sheetEntitys, OutputStream out){
		try {
			return templateExportExcel(new File(templatePath),sheetEntitys, out);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 通过模板写入数据
	 * @param templateFile	模板文件
	 * @param sheetEntitys  配置属性和数据
	 * @param out		输出流
	 * @return
	 */
	public static Workbook templateExportExcel(File templateFile,List<SheetEntity> sheetEntitys, OutputStream out){
		Workbook workbook = null;
		InputStream inputStream = null;
		try {
			inputStream = new FileInputStream(templateFile);
			workbook = templateExportExcel(new FileInputStream(templateFile),sheetEntitys, out);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}finally {
			if(inputStream != null){
				try {
					inputStream.close();
				} catch (Exception e) {
					throw new RuntimeException(e);
				}
			}
		}
		return workbook;
	}


	/**
	 * 通过模板写入数据
	 * @param inputStream  模板文件输入流
	 * @param sheetEntitys  配置属性和数据
	 * @param out			输出流
	 * @return
	 */
	public static Workbook templateExportExcel(InputStream inputStream, List<SheetEntity> sheetEntitys, OutputStream out){
		Workbook workbook = null;
		try {
			workbook = WorkbookFactory.create(inputStream);
			for (SheetEntity sheetEntity: sheetEntitys) {
				sheetEntity.setWorkbook(workbook);
				templateExportExcel(sheetEntity);
			}

			workbook.write(out);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}

		return workbook;
	}

	private static void templateExportExcel(SheetEntity sheetEntity){
		if(sheetEntity.getTemplateDate() != null){
			sheetEntity.replaceTemplate();
		}

		if(VerifyObject.isNotEmpty(sheetEntity.getData())){
			createExcel(sheetEntity);
		}
	}

}
